using Microsoft.Ccr.Core;
using Microsoft.Dss.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.Core.DsspHttp;
using Microsoft.Dss.Core.DsspHttpUtilities;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using Microsoft.Robotics.PhysicalModel.Proxy;
using System;
using System.Net;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Security.Permissions;
using xml = System.Xml;
using W3C.Soap;

using gpio = Microsoft.Robotics.Services.GpioPinArray.Proxy;
using vex = VEXRobotics.Proxy;
using submgr = Microsoft.Dss.Services.SubscriptionManager;

namespace VEXService.Gpio
{
    /// <summary>
    /// GpioSensor Port
    /// </summary>
    [ServicePort]
    public class VEXGpioOperations : PortSet<
        DsspDefaultLookup,
        DsspDefaultDrop,
        Get,
        HttpGet,
        HttpPost,
        gpio.Replace,
        gpio.ReliableSubscribe,
        gpio.Subscribe,
        gpio.SetPin>
    {
    }


    // Summary:
    //     List of GPIO pins
    [Description("List of GPIO pins")]
    [DataContract]
    public class VEXGpioPinState : IDssSerializable, ICloneable
    {
        // Summary:
        //     Gets or sets pin name
        [Description("Friendly identifier for the pin.")]
        [DataMember(Order = -1)]
        public string Name;

        //
        // Summary:
        //     Gets or sets pin location identifier
        [DataMember(Order = -1)]
        [Description("Location identifier for the pin.")]
        public vex.SensorPort SensorPort;

        //
        // Summary:
        //     Gets or sets pin direction
        [Description("Data direction for the pin.")]
        [DataMember(Order = -1)]
        public gpio.GpioPinState.GpioPinDirection PinDirection;

        //
        // Summary:
        //     Gets or sets pin signal
        [DataMember(Order = -1)]
        [Description("Voltage state of the pin.")]
        public gpio.GpioPinState.GpioPinSignal PinState;

        //
        // Summary:
        //     Gets or sets timestamp of this sample
        [DataMember(Order = -1, XmlOmitDefaultValue = true)]
        [Description("Indicates the timestamp of the pin state.")]
        [Browsable(false)]
        [DefaultValue(typeof(DateTime), "0001-01-01T00:00:00")]
        public DateTime TimeStamp;

        /// <summary>
        /// Copy To Gyro sensor state
        /// </summary>
        public virtual void CopyTo(IDssSerializable target)
        {
            VEXGpioPinState typedTarget = target as VEXGpioPinState;

            if (typedTarget == null)
                throw new ArgumentException("CopyTo({0}) requires type {0}", this.GetType().FullName);

            typedTarget.Name = this.Name;
            typedTarget.PinDirection = this.PinDirection;
            typedTarget.PinState = this.PinState;
            typedTarget.SensorPort = this.SensorPort;
            typedTarget.TimeStamp = this.TimeStamp;
        }
        
        /// <summary>
        /// Clone Gyro sensor state
        /// </summary>
        public object Clone()
        {
            VEXGpioPinState clone = new VEXGpioPinState();

            clone.Name = this.Name;
            clone.SensorPort = this.SensorPort;
            clone.PinDirection = this.PinDirection;
            clone.PinState = this.PinState;
            clone.TimeStamp = this.TimeStamp;

            return clone;
        }

        public gpio.GpioPinState ToGenericState(gpio.GpioPinState genericState)
        {
            genericState.Name = this.Name;
            genericState.Number = (int)this.SensorPort;
            genericState.PinDirection = this.PinDirection;
            genericState.PinState = this.PinState;
            genericState.TimeStamp = this.TimeStamp;

            return genericState;
        }

        /// <summary>
        /// Serialize
        /// </summary>
        public void Serialize(System.IO.BinaryWriter writer)
        {
            writer.Write(this.Name);
            writer.Write((int)this.PinDirection);
            writer.Write((int)this.PinState);
            writer.Write((int)this.SensorPort);
            Microsoft.Dss.Services.Serializer.BinarySerializationHelper.SerializeDateTime(TimeStamp, writer);
        }


        /// <summary>
        /// Deserialize
        /// </summary>
        public virtual object Deserialize(System.IO.BinaryReader reader)
        {
            Name = reader.ReadString();
            PinDirection = (gpio.GpioPinState.GpioPinDirection)reader.ReadInt32();
            PinState = (gpio.GpioPinState.GpioPinSignal)reader.ReadInt32();
            SensorPort = (vex.SensorPort)reader.ReadInt32();
            TimeStamp = Microsoft.Dss.Services.Serializer.BinarySerializationHelper.DeserializeDateTime(reader);
            return this;
        }
    }

    /// <summary>
    /// Additional configuration which is necessary to 
    /// configure a digital IO.
    /// </summary>
    [DataContract]
    public class VEXGpioPinArrayState : IDssSerializable, ICloneable
    {

        // Summary:
        //     Gets or sets the list of pins
        [DataMember(Order = -1)]
        [Description("The set of GPIO pins.")]
        public List<VEXGpioPinState> Pins;

        public VEXGpioPinArrayState()
        {
            Pins = new List<VEXGpioPinState>();
        }

        /// <summary>
        /// Transform current state to the specified generic state.
        /// </summary>
        /// <param name="genericState"></param>
        /// <returns></returns>
        public gpio.GpioPinArrayState ToGenericState(gpio.GpioPinArrayState genericState)
        {
            genericState.Pins.Clear();
            foreach (VEXGpioPinState pin in Pins)
            {
                gpio.GpioPinState genericPinState = new gpio.GpioPinState();
                genericState.Pins.Add(pin.ToGenericState(genericPinState));
            }
            return genericState;
        }
        /// <summary>
        /// Copy generic state to this state, transforming data members.
        /// </summary>
        /// <param name="genericState"></param>
        public void FromGenericState(gpio.GpioPinArrayState genericState)
        {
            Pins.Clear();
            foreach (gpio.GpioPinState pin in genericState.Pins)
            {
                if (pin.Number >= 0 && pin.Number <= 16)
                {
                    VEXGpioPinState newState = new VEXGpioPinState();
                    newState.Name = pin.Name;
                    newState.PinDirection = pin.PinDirection;
                    newState.PinState = pin.PinState;
                    newState.SensorPort = (vex.SensorPort)pin.Number;
                    newState.TimeStamp = pin.TimeStamp;
                    Pins.Add(newState);
                }
            }
        }


        #region IDssSerializable

        /// <summary>
        /// Copy To Digital IO sensor state
        /// </summary>
        public virtual void CopyTo(IDssSerializable target)
        {
            VEXGpioPinArrayState typedTarget = target as VEXGpioPinArrayState;

            if (typedTarget == null)
                throw new ArgumentException("CopyTo({0}) requires type {0}", this.GetType().FullName);

            typedTarget.Pins.Clear();
            foreach (VEXGpioPinState pin in Pins)
            {
                typedTarget.Pins.Add((VEXGpioPinState) pin.Clone());
            }
        }

        /// <summary>
        /// Clone the VEX GPIO State
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            VEXGpioPinArrayState clone = new VEXGpioPinArrayState();
            foreach (VEXGpioPinState pin in Pins)
            {
                clone.Pins.Add((VEXGpioPinState)pin.Clone());
            }

            return clone;
        }

        /// <summary>
        /// Serialize
        /// </summary>
        public virtual void Serialize(System.IO.BinaryWriter writer)
        {
            writer.Write(this.Pins.Count);
            foreach (VEXGpioPinState pin in Pins)
            {
                pin.Serialize(writer);
            }
        }

        /// <summary>
        /// Deserialize
        /// </summary>
        public virtual object Deserialize(System.IO.BinaryReader reader)
        {
            Pins.Clear();
            int cnt = reader.ReadInt32();
            for(int i=0; i<cnt; ++i)
            {
                VEXGpioPinState newPin = new VEXGpioPinState();
                newPin.Deserialize(reader);
                Pins.Add(newPin);
            }

            return this;
        }
        #endregion
    }


    /// <summary>
    /// Get the VEX Digital IO State
    /// </summary>
    [Description("Gets the current state of the VEX Digital IO Sensor.")]
    public class Get : Get<GetRequestType, PortSet<VEXGpioPinArrayState, Fault>>
    {
    }
    

    /// <summary>
    /// VEX Digital IO Contract 
    /// </summary>
    public sealed class Contract
    {
        public const string Identifier = "http://schemas.vexrobotics.com/2011/09/vexservice.gpio.html";
    }


    [Contract(Contract.Identifier)]
    [AlternateContract(gpio.Contract.Identifier)]
    [DisplayName("VEX GPIO")]
    [Description("Provides access to the VEX Digital IO")]
    [DssCategory(vex.VEXCategories.VEX)]
    public class VEXGpio : DsspServiceBase
    {
        /// <summary>
        /// XSLT Transform to use for display
        /// </summary>
        [EmbeddedResource("VEXService.Config.Gpio.xslt")]
        private string _transform = null;

        /// <summary>
        /// Sensor state
        /// </summary>
        [InitialStatePartner(Optional = true, ServiceUri = ServicePaths.Store + @"/VEX.Gpio.config.xml")]
        private VEXGpioPinArrayState _State = new VEXGpioPinArrayState();

        /// <summary>
        /// Service port
        /// </summary>
        [ServicePort("/VEX/Gpio", AllowMultipleInstances = true)]
        private VEXGpioOperations _mainPort = new VEXGpioOperations();

        /// <summary>
        /// Port to talk with the VEX controller
        /// </summary>
        [Partner("VEX", Contract = vex.Contract.Identifier,
            CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate,
            Optional = false)]
        private vex.VEXOperations _vexPort = new vex.VEXOperations();

        // VEX Notifications
        vex.VEXOperations _notificationPort = new vex.VEXOperations();

        // Create a local GPIO for convenience
        [AlternateServicePort("/gpio",
            AllowMultipleInstances = true,
            AlternateContract = gpio.Contract.Identifier)]
        private gpio.GpioPinArrayOperations _genericPort = new gpio.GpioPinArrayOperations();


        /// <summary>
        /// HTTP helper
        /// </summary>
        DsspHttpUtilitiesPort _httpUtilities = new DsspHttpUtilitiesPort();

        /// <summary>
        /// Subscription manager
        /// </summary>
        [Partner("SubMgr", Contract = submgr.Contract.Identifier,
            CreationPolicy = PartnerCreationPolicy.CreateAlways,
            Optional = false)]
        private submgr.SubscriptionManagerPort _subMgrPort = new submgr.SubscriptionManagerPort();

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="creationPort"></param>
        public VEXGpio(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {
        }

        #region Initialization Code

        /// <summary>
        /// Startup
        /// </summary>
        protected override void Start()
        {
            LogVerbose(LogGroups.Console, "Configuring VEX GPIO... ");

            // Listen for each of my handlers
            ActivateDsspOperationHandlers();

            // Publish the service to the local Node Directory
            DirectoryInsert();

            #region Initialize Service State
            Port<bool> donePort = new Port<bool>();
            if (_State == null)
            {
                _State = new VEXGpioPinArrayState();
            }
            else
            {
                SpawnIterator<Port<bool>>(donePort, SetGpioConnection);
            }

            Activate(Arbiter.Receive(false, donePort,
                delegate(bool success)
                {
                    if (success)
                    {
                        // display HTTP service Uri
                        LogInfo(LogGroups.Console, "Service uri: ");
                    }
                    else
                    {
                        LogError(LogGroups.Console, "VEX GPIO service failed to start.");
                        _mainPort.Post(new DsspDefaultDrop());
                    }

                }));
            #endregion

            // Needed for HttpPost
            _httpUtilities = DsspHttpUtilitiesService.Create(Environment);
        }

        /// <summary>
        /// Set the configuration
        /// </summary>
        /// <param name="donePort"></param>
        /// <returns></returns>
        private IEnumerator<ITask> SetGpioConnection(Port<bool> donePort)
        {
            bool serviceSuccess = true;

            // Configure default state
            foreach (VEXGpioPinState pin in _State.Pins)
            {
                vex.SelectivePortConfigure newConfig = new vex.SelectivePortConfigure();
                newConfig.Body.Port = pin.SensorPort;
                newConfig.Body.Type = (pin.PinDirection == gpio.GpioPinState.GpioPinDirection.In) ?
                    vex.SensorDefinition.SensorType.DigitalInput : vex.SensorDefinition.SensorType.DigitalOutput;

                _vexPort.Post(newConfig);
                yield return Arbiter.Choice(newConfig.ResponsePort,
                    delegate(DefaultReplaceResponseType response)
                    {
                    },
                    delegate(Fault fault)
                    {
                        serviceSuccess = false;
                        LogError(LogGroups.Console, "Failed to update VEX service configuration", fault);
                    });

                if (pin.PinDirection == gpio.GpioPinState.GpioPinDirection.Out)
                {
                    SetPinOnVEX(pin);
                }
            }

            // Subscribe to VEX for notifications
            if (serviceSuccess)
            {
                serviceSuccess = false;
                SaveState(_State);
                Port<bool> subscribeDonePort = new Port<bool>();
                SpawnIterator<Port<bool>>(subscribeDonePort, SubscribeToVEX);
                yield return (Arbiter.Receive<bool>(false, subscribeDonePort,
                    delegate(bool success)
                    {
                        serviceSuccess = success;
                    }));
            }

            donePort.Post(serviceSuccess);
            yield break;
        }

        /// <summary>
        /// Subscribe to the port on VEX
        /// Hook up notifications
        /// and then post success or failure
        /// <param name="successPort"></param>
        /// </summary>
        private IEnumerator<ITask> SubscribeToVEX(Port<bool> successPort)
        {
            //create a custom subscription request
            vex.CustomSubscribeRequestType request = new vex.CustomSubscribeRequestType();

            //select only the sensor and port we want
            //NOTE: this name must match the VEX sensor name.
            request.Sensors = new List<vex.SensorDefinition>();

            foreach (VEXGpioPinState pin in _State.Pins)
            {
                vex.SensorDefinition sensor = new vex.SensorDefinition();
                sensor.Type = pin.PinDirection == gpio.GpioPinState.GpioPinDirection.In ?
                    vex.SensorDefinition.SensorType.DigitalInput : vex.SensorDefinition.SensorType.DigitalOutput;
                sensor.Port = pin.SensorPort;
                request.Sensors.Add(sensor);
            }

            //Subscribe to the VEX and wait for a response
            bool subscribed = false;
            yield return
                Arbiter.Choice(_vexPort.SelectiveSubscribe(request, _notificationPort),
                    delegate(SubscribeResponseType Rsp)
                    {
                        //Subscription was successful, start listening for change notifications
                        Activate(
                            Arbiter.Receive<vex.Update>(true, _notificationPort, SensorNotificationHandler)
                        );

                        //update our state with subscription status
                        subscribed = true;
                    },
                    delegate(Fault fault)
                    {
                        LogError("GPIO subscription failed", fault);
                        successPort.Post(false);
                    }
                );

            successPort.Post(subscribed);
            yield break;
        }

        #endregion

        #region Internal Port Handlers

        /// <summary>
        /// Handle update message from VEX
        /// </summary>
        private void SensorNotificationHandler(vex.Update notify)
        {
            //update state
            bool changed = false;
            foreach(VEXGpioPinState pin in _State.Pins)
            {
                if(pin.SensorPort != vex.SensorPort.SensorPort_None)
                {
                    ushort value = notify.Body.PortSensors.Sensors[(int)pin.SensorPort - 1].Value;
                    gpio.GpioPinState.GpioPinSignal origValue = pin.PinState;
                    pin.PinState = (value == 0) ? gpio.GpioPinState.GpioPinSignal.Low : gpio.GpioPinState.GpioPinSignal.High;
                    changed |= origValue != pin.PinState;
                    pin.TimeStamp = DateTime.Now;
                }
            }

            if (changed)
            {
                //notify subscribers on any change
                gpio.GpioPinArrayState genericState = new gpio.GpioPinArrayState();
                genericState.Pins = new List<gpio.GpioPinState>();
                SendNotification<gpio.Replace>(_subMgrPort, _State.ToGenericState(genericState));
            }
        }



        #endregion

        #region Standard Operation Handlers

        /// <summary>
        /// Get the state
        /// </summary>
        /// <param name="get"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public IEnumerator<ITask> GetHandler(Get get)
        {
            get.ResponsePort.Post(_State);
            yield break;
        }

        /// <summary>
        /// Get the state
        /// </summary>
        /// <param name="get"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Concurrent, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> GpioGetHandler(gpio.Get get)
        {
            gpio.GpioPinArrayState genericState = new gpio.GpioPinArrayState();
            _State.ToGenericState(genericState);
            get.ResponsePort.Post(genericState);
            yield break;
        }

        /// <summary>
        /// Get the state to HTTP display
        /// </summary>
        /// <param name="httpGet">Response port to post the state</param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        [ServiceHandler(ServiceHandlerBehavior.Concurrent, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> HttpGetHandler(HttpGet httpGet)
        {
            httpGet.ResponsePort.Post(new HttpResponseType(
                HttpStatusCode.OK,
                _State,
                _transform)
            );
            yield break;
        }


        /// <summary>
        /// HttpPost Handler
        /// </summary>
        /// <param name="submit"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> HttpPostHandler(HttpPost httpPost)
        {
            // Use helper to read form data
            ReadFormData readForm = new ReadFormData(httpPost);
            _httpUtilities.Post(readForm);

            // Wait for result
            Activate(Arbiter.Choice(readForm.ResultPort,
                delegate(NameValueCollection parameters)
                {
                    FormDigitalOutput(httpPost, parameters);
                    HttpPostSuccess(httpPost);
                },
                delegate(Exception fault)
                {
                    LogError(fault.Message);
                    HttpPostFailure(httpPost, fault.Message);
                })
            );
            yield break;
        }


        /// <summary>
        /// Set the digital output
        /// </summary>
        /// <param name="httpPost"></param>
        /// <param name="parameters"></param>
        private void FormDigitalOutput(HttpPost httpPost, NameValueCollection parameters)
        {
            // See if a specific port changed
            bool configChanged = false;
            VEXGpioPinArrayState newState = (VEXGpioPinArrayState) _State.Clone();
            for (int i = 0; i < _State.Pins.Count; i++)
            {
                if (_State.Pins[i].PinDirection == gpio.GpioPinState.GpioPinDirection.Out)
                {
                    if ((parameters["button_set_" + (i + 1)] != null) ||
                        (parameters["SetValues"] != null))
                    {
                        // Set output i
                        gpio.GpioPinState.GpioPinSignal oldValue = _State.Pins[i].PinState;
                        _State.Pins[i].PinState = (null != parameters["output_set_" + (i + 1)]) ?
                            gpio.GpioPinState.GpioPinSignal.High : gpio.GpioPinState.GpioPinSignal.Low;
                        if (_State.Pins[i].PinState != oldValue)
                        {
                            SetPinOnVEX(_State.Pins[i]);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Send Http Post Success Response
        /// </summary>
        /// <param name="httpPost"></param>
        private void HttpPostSuccess(HttpPost httpPost)
        {
            HttpResponseType rsp =
                new HttpResponseType(HttpStatusCode.OK, _State, _transform);
            httpPost.ResponsePort.Post(rsp);
        }

        /// <summary>
        /// Send Http Post Failure Response
        /// </summary>
        /// <param name="httpPost"></param>
        /// <param name="failureReason"></param>
        private static void HttpPostFailure(HttpPost httpPost, string failureReason)
        {
            HttpResponseType rsp =
                new HttpResponseType(HttpStatusCode.ExpectationFailed, failureReason);
            httpPost.ResponsePort.Post(rsp);
        }
        
        /// <summary>
        /// Replace the state with the given update
        /// </summary>
        /// <param name="replace">Replacement state</param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        [ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> ReplaceHandler(gpio.Replace replace)
        {
            if (replace.Body.Pins.Count != _State.Pins.Count)
            {
                Fault fault = Fault.FromException(new InvalidOperationException("Invalid number of sensors"));
                replace.ResponsePort.Post(fault);
                yield break;
            }
            for (int i = 0; i < replace.Body.Pins.Count; ++i)
            {
                if ((int)_State.Pins[i].SensorPort != replace.Body.Pins[i].Number)
                {
                    Fault fault = Fault.FromException(new InvalidOperationException("Cannot reassign sensor ports"));
                    replace.ResponsePort.Post(fault);
                    yield break;
                }
            }

            _State.FromGenericState(replace.Body);
            SaveState(_State);

            gpio.GpioPinArrayState genericState = new gpio.GpioPinArrayState();
            genericState.Pins = new List<gpio.GpioPinState>();
            SendNotification<gpio.Replace>(_subMgrPort, _State.ToGenericState(genericState));
            replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
            yield break;
        }

        /// <summary>
        /// Subscribe to updates
        /// </summary>
        /// <param name="subscribe"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        [ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> SubscribeHandler(gpio.Subscribe subscribe)
        {
            yield return Arbiter.Choice(
                SubscribeHelper(_subMgrPort, subscribe.Body, subscribe.ResponsePort),
                delegate(SuccessResult success)
                {
                    ProcessSubscribeResponse(subscribe.Body.Subscriber);
                },
                delegate(Exception fault)
                {
                    LogError(fault);
                }
            );
        }

        /// <summary>
        /// ReliableSubscribe Handler
        /// </summary>
        /// <param name="subscribe"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        [ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> ReliableSubscribeHandler(gpio.ReliableSubscribe subscribe)
        {
            yield return Arbiter.Choice(
                SubscribeHelper(_subMgrPort, subscribe.Body, subscribe.ResponsePort),
                delegate(SuccessResult success)
                {
                    ProcessSubscribeResponse(subscribe.Body.Subscriber);
                },
                delegate(Exception fault)
                {
                    LogError(fault);
                }
            );
        }

        
        /// <summary>
        /// SetPin Handler
        /// </summary>
        /// <param name="subscribe"></param>
        /// <returns></returns>
        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        [ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_genericPort")]
        public IEnumerator<ITask> SetPinHandler(gpio.SetPin pinData)
        {
            if (pinData.Body.PinState.Number >= 0 &&
                pinData.Body.PinState.Number < _State.Pins.Count)
            {
                _State.Pins[pinData.Body.PinState.Number].Name = pinData.Body.PinState.Name;
                _State.Pins[pinData.Body.PinState.Number].PinDirection = pinData.Body.PinState.PinDirection;
                _State.Pins[pinData.Body.PinState.Number].PinState = pinData.Body.PinState.PinState;
                _State.Pins[pinData.Body.PinState.Number].TimeStamp = pinData.Body.PinState.TimeStamp;
                SetPinOnVEX(_State.Pins[pinData.Body.PinState.Number]);
            }
            yield break;
        }

        /// <summary>
        /// Set a pin on the VEX processor
        /// </summary>
        /// <param name="pin">Pin data to set</param>
        private void SetPinOnVEX(VEXGpioPinState pin)
        {
            vex.SetOutputPortRequest sop = new vex.SetOutputPortRequest();
            if((pin.SensorPort != vex.SensorPort.SensorPort_None) &&
               (pin.PinDirection == gpio.GpioPinState.GpioPinDirection.Out))
            {
                vex.SetOutputPort port = new vex.SetOutputPort();
                port.Port = pin.SensorPort;
                port.State = pin.PinState == gpio.GpioPinState.GpioPinSignal.High;
                sop.Body.UpdatePorts = new List<vex.SetOutputPort>();
                sop.Body.UpdatePorts.Add(port);
                _vexPort.Post(sop);
                Activate(
                    Arbiter.Choice(
                        Arbiter.Receive<DefaultUpdateResponseType>(false, sop.ResponsePort,
                            delegate(DefaultUpdateResponseType response)
                            {
                                ;
                            }),
                        Arbiter.Receive<Fault>(false, sop.ResponsePort,
                            delegate(Fault fault)
                            {
                                LogError("GPIO update failed", fault);
                            })
                    )
                );
            }
        }

        #endregion

        #region Subroutines

        /// <summary>
        /// Process the subscription response
        /// </summary>
        /// <param name="subscriber"></param>
        private void ProcessSubscribeResponse(string subscriber)
        {
            gpio.GpioPinArrayState genericState = new gpio.GpioPinArrayState();
            genericState.Pins = new List<gpio.GpioPinState>();
            SendNotification<gpio.Replace>(_subMgrPort, _State.ToGenericState(genericState));
        }

        #endregion
    }
}
